<?php

namespace App\Models\Traits;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Log;

trait HasTree
{
    public function getTree($parent_id = 0, $hasRoot = false, $where = null, $label = 'name', $top = '顶级', $order = 'order')
    {
        $primaryKey = $this->primaryKey ?? 'id';
        $result = collect();
        $modelName = get_class($this);
        $model = new $modelName();
        if ($where) {
            $model = $model->where($where);
        }
        $datas = $model->where('parent_id', $parent_id)->orderBy($order)->get();
        foreach ($datas as &$data) {
            $cnt = $where ? $data->children()->where($where)->count() : $data->children()->count();
            $item = collect([
                'id' => $data->{$primaryKey} . '',
                'label' => $data->{$label},
                'isLeaf' => $cnt != 0,
                'breadIds' => $data->breadIds,
                'breadcrumbs' => $data->breadcrumbs,
                'status' => $data->status,
                'creator' => $data->creator->name ?? '',
//                'createdAt' => $data->{$createdAt}->format('Y-m-d'),
            ]);
//            Log::debug('HasTree getTree', ['id' => $data->{$primaryKey}]);
            $children = $this->getTree($data->{$primaryKey}, false, $where, $label, $top, $order);
            if ($children) {
                $item->put('children', $children);
            }
            $result->push($item);
        }

        if ($hasRoot) {
            $root = [
                'id' => '0',
                'label' => $top,
                'fullName' => $top,
            ];
            if ($result->count() > 0) {
                $root['children'] = $result->toArray();
                $root['isLeaf'] = true;
            }
            return collect([$root]);
        } else {
            return $result->count() > 0 ? $result : null;
        }
    }

    public function parent(): BelongsTo
    {
        return $this->belongsTo(self::class, 'parent_id');
    }

    public function children(): HasMany
    {
        return $this->hasMany(self::class, 'parent_id');
    }

    public function breadIds(): Attribute
    {
        $primaryKey = $this->primaryKey ?? 'id';
        $result = collect([$this->{$primaryKey}]);
        $theParent = $this->parent;
        while ($theParent) {
            $result->prepend($theParent->{$primaryKey});
            $theParent = $theParent->parent;
        }
        return Attribute::make(
            get: fn () => $result,
        )->withoutObjectCaching();
    }

    public function breadcrumbs(): Attribute
    {
        $result = collect([$this->name]);
        $theParent = $this->parent;
        while ($theParent) {
            $result->prepend($theParent->name);
            $theParent = $theParent->parent;
        }
        return Attribute::make(
            get: fn () => $result,
        )->withoutObjectCaching();
    }

    public function label(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->name,
        )->withoutObjectCaching();
    }

    public function isLeaf(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->children()->count() > 0,
        )->withoutObjectCaching();
    }

    public function getChilds($parent = null) {
        $parent = $parent ?? $this;
        $result = collect();
        $result->push($parent);
        $datas = $parent->children;
        foreach ($datas as &$data) {
            $children = $this->getChilds($data);
            if ($children) {
                $result = $result->merge($children);
            }
        }
        return $result;
    }
}
